#ifndef __WIZ_ALGEBRA_TRIGONOMETRY_HPP__SHANHAOBO_19800429__
#define __WIZ_ALGEBRA_TRIGONOMETRY_HPP__SHANHAOBO_19800429__

#include "../../../../WizCore/Include/Base/Cast/WizBaseCast.hpp"
#include "../../../../WizCore/Include/Base/Type/WizBaseType.hpp"
#include "../../../../WizCore/Include/Base/Utils/WizBaseUtilsSingleton.hpp"
#include "./WizAlgebraTrigonometryTable.hpp"

namespace Wiz
{
    namespace Trigonometry
    {
        struct Type : public ::Wiz::Singleton::Type<::Wiz::Trigonometry::Type>
        {
            Type();
            virtual ~Type();
        public:
            WIZ_INLINE ::Wiz::Real::Type GetSinByIndex(::Wiz::Int::In i) const
            {
                return m_TablePtr->GetSinByIndex(i);
            }
            WIZ_INLINE ::Wiz::Real::Type GetCosByIndex(::Wiz::Int::In i) const
            {
                return m_TablePtr->GetCosByIndex(i);
            }
            WIZ_INLINE ::Wiz::Real::Type GetASinByIndex(::Wiz::Int::In i) const
            {
                return m_TablePtr->GetASinByIndex(i);
            }
            WIZ_INLINE ::Wiz::Real::Type GetACosByIndex(::Wiz::Int::In i) const
            {
                return m_TablePtr->GetACosByIndex(i);
            }
            WIZ_INLINE ::Wiz::Real::Type GetTanByIndex(::Wiz::Int::In i) const
            {
                return m_TablePtr->GetTanByIndex(i);
            }
        public:
            WIZ_INLINE ::Wiz::Real::Type Sin(::Wiz::Real::In Angle) const
            {
                return GetSinByIndex(m_TablePtr->AngleToIndex(Angle));
            }
            WIZ_INLINE ::Wiz::Real::Type ASin(::Wiz::Real::In Value) const
            {
                return GetASinByIndex(m_TablePtr->ValueToIndex(Value));
            }
            WIZ_INLINE ::Wiz::Real::Type Cos(::Wiz::Real::In Angle) const
            {
                return GetCosByIndex(m_TablePtr->AngleToIndex(Angle));
            }
            WIZ_INLINE ::Wiz::Real::Type ACos(::Wiz::Real::In Value) const
            {
                return GetACosByIndex(m_TablePtr->ValueToIndex(Value));
            }
            WIZ_INLINE ::Wiz::Real::Type Tan(::Wiz::Real::In Angle) const
            {
                return GetTanByIndex(m_TablePtr->AngleToIndex(Angle));
            }
            WIZ_INLINE ::Wiz::Void::Type SinCos(::Wiz::Real::Out s, ::Wiz::Real::Out c, ::Wiz::Real::In v) const
            {
                s = this->Sin(v);
                c = this->Cos(v);
            }
            WIZ_INLINE ::Wiz::Real::Type ATan2(::Wiz::Real::In y, ::Wiz::Real::In x) const
            {
                return ::atan2(y, x);
            }
        private:
            ::Wiz::Trigonometry::Table::Ptr m_TablePtr;
        };
        WIZ_SINGLETON_NAMESPACE(::Wiz::Trigonometry::Type);
    } /// end of namespace Trigonometry



    //////////////////////////////////////////////////////////////////////////
    template<typename T>
    WIZ_INLINE T ACos(const T& v)
    {
        return ::Wiz::Cast::Static<T>(::acos(::Wiz::Cast::Static<double>(v)));
    }

    template<typename T>
    WIZ_INLINE T ASin(const T& v)
    {
        return ::Wiz::Cast::Static<T>(::asin(::Wiz::Cast::Static<double>(v)));
    }

    template<typename T>
    WIZ_INLINE T ATan(const T& v)
    {
        return ::Wiz::Cast::Static<T>(::atan(::Wiz::Cast::Static<double>(v)));
    }

    template<typename T>
    WIZ_INLINE T ATan2(const T& numerator, const T& denominator)
    {
        return ::Wiz::Cast::Static<T>(::atan2(::Wiz::Cast::Static<double>(numerator), ::Wiz::Cast::Static<double>(denominator)));
    }

    template<typename T>
    WIZ_INLINE T Cos(const T& v)
    {
        return ::Wiz::Cast::Static<T>(::cos(::Wiz::Cast::Static<double>(v)));
    }

    template<typename T>
    WIZ_INLINE T Sin(const T& v)
    {
        return ::Wiz::Cast::Static<T>(::sin(::Wiz::Cast::Static<double>(v)));
    }

    template<typename T>
    WIZ_INLINE T Tan(const T& v)
    {
        return ::Wiz::Cast::Static<T>(::tan(::Wiz::Cast::Static<double>(v)));
    }

    template<typename T>
    WIZ_INLINE ::Wiz::Void::Type SinCos(T& OSin, T& OCos, const T& Ang)
    {
        float s, c;

        __asm fld  Ang
            __asm fsincos
            __asm fstp c
            __asm fstp s

            OSin = s;
        OCos = c;
    }
    //////////////////////////////////////////////////////////////////////////

    //////////////////////////////////////////////////////////////////////////
    WIZ_INLINE ::Wiz::Real::Type ACosFast(::Wiz::Real::In v)
    {
        return ::Wiz::Trigonometry::SingletonRef().ACos(v);
    }
    WIZ_INLINE ::Wiz::Real::Type ASinFast(::Wiz::Real::In v)
    {
        return ::Wiz::Trigonometry::SingletonRef().ASin(v);
    }
    WIZ_INLINE ::Wiz::Real::Type ATanFast(::Wiz::Real::In InVal)
    {
        return ::Wiz::ATan(InVal);
    }
    WIZ_INLINE ::Wiz::Real::Type ATan2Fast(::Wiz::Real::In y, ::Wiz::Real::In x) 
    {
        return ::Wiz::Trigonometry::SingletonRef().ATan2(y, x);
    }

    WIZ_INLINE ::Wiz::Real::Type CosFast(::Wiz::Real::In Ang)
    {
        return ::Wiz::Trigonometry::SingletonRef().Cos(Ang);
    }
    WIZ_INLINE ::Wiz::Real::Type SinFast(::Wiz::Real::In Ang)
    {
        return ::Wiz::Trigonometry::SingletonRef().Sin(Ang);
    }
    WIZ_INLINE ::Wiz::Real::Type TanFast(::Wiz::Real::In angle)
    {
        return ::Wiz::Trigonometry::SingletonRef().Tan(angle);
    }
    WIZ_INLINE ::Wiz::Void::Type SinCosFast(::Wiz::Real::Out OSin, ::Wiz::Real::Out OCos, ::Wiz::Real::In Ang)
    {
        //::Wiz::Trigonometry::SingletonRef().SinCos(OSin, OCos, Ang);
        ::Wiz::SinCos(OSin, OCos, Ang);
    }
    ////////////////////////////////////////////////////////////////////////
} /// end of namespace Wiz

#endif /*__WIZ_ALGEBRA_TRIGONOMETRY_HPP__SHANHAOBO_19800429__*/
